#include "modbus_user.h"
#include "modbus_slave.h"
#include "modbus_poll.h"

// 测试从机
SlaveReg         MB_00   = {0};

// 测试主机
MasterReg myData  = {0};
MasterReg myData2 = {0};

MasterUnit unitList[2] = {
    {0x01, 0x03, 0x0000, 6, (uint16_t*)&myData},
    {0x01, 0x03, 0x000a, 2, (uint16_t*)&myData2},
};

/**
 * @brief Modbus从机回调函数：寄存器读取函数.
 * @note  该函数在从机处理函数中调用，用于读取从机寄存器的值.
 * @param 
 *   - reg          寄存器地址 (高8位为类型, 低8位为偏移地址).
 *   - _size        读取寄存器数量.
 *   - *val         输出数据缓冲区指针.
 *
 * @return ModbusException 异常码
 */
ModbusException ModbusRead(uint16_t reg, uint16_t _size, uint16_t *val)
{
    uint16_t *tmp;
    uint16_t i       = 0;
    uint8_t  RegType = reg >> 8;
    uint8_t  addr    = (uint8_t)reg & 0xff;
    if(RegType == 0)
    {
        tmp = (uint16_t*)&MB_00;
        if(addr <= REG_SIZE && addr + _size <= REG_SIZE)
        {
            for(; i < _size; i++)
            {
                *(val + i) = tmp[addr + i];
            }       
            return MODBUS_EX_NONE;
        }
    }
    return MODBUS_EX_ILLEGAL_ADDRESS;
}

/**
 * @brief Modbus从机回调函数：寄存器写入函数.
 * @note  该函数在从机处理函数中调用，用于写入从机寄存器的值.
 * @param 
 *   - reg          寄存器地址 (高8位为类型, 低8位为偏移地址).
 *   - val          写入值.
 *
 * @return ModbusException 异常码
 */
ModbusException ModbusWrite(uint16_t reg, uint16_t val)
{
    uint16_t *tmp;
    uint8_t RegType = reg >> 8;
    uint8_t addr    = (uint8_t)reg & 0xff;

    if(RegType == 0x01)     return MODBUS_EX_ILLEGAL_ADDRESS;

    tmp = (uint16_t*)&MB_00;
    if(addr <= REG_SIZE)
    {
        tmp[addr] = val;
        return MODBUS_EX_NONE;
    }
    return MODBUS_EX_ILLEGAL_ADDRESS;
}

/**
 * @brief Modbus主机、从机初始化函数.
 * @param 
 *   - void
 *
 * @return void
 */
void ModbusInit(void)
{
    ModbusSlavePort  port_s;
    ModbusMasterPort port_m;
    SlaveCallBacks callbacks;

    port_m.uart_send = uart2.send;
    port_m.get_timestamp_ms = GetTick;
    ModbusMaterCreate(&master, &port_m, 1000);

    port_s.uart_send = uart1.send;
    port_s.get_timestamp_ms = GetTick;
    callbacks.read_holding_registers = &ModbusRead;
    callbacks.write_single_register = &ModbusWrite;
    ModbusSlaveCreate(&slave, 0x01, &port_s, &callbacks, 4);  // 从机地址设为0x01
}

/**
 * @brief Modbus主机处理函数.
 * @param 
 *   - void
 *
 * @return void
 */
void ModbusMasterProcess(void)
{
    ModbusException ex;
    static int i = 0;
    switch (master.state)
    {
    case MB_IDLE:        
        MasterReadRegisters(&master, unitList[i].id, unitList[i].addr, unitList[i].len);  
        break;
    case MB_WAITING_RESPONSE:
        MasterPoll(&master, uart2.queue);
        if (master.state == MB_RESPONSE_RECEIVED) 
        {
            ex = MasterGetReadResult(&master, unitList[i].rec, unitList[i].len);
            if (ex == MODBUS_EX_NONE) 
            {
                i++;
                if(i >= UNIT_SIZE)
                    i = 0;
            }  
        }else if( master.state == MB_TIMEOUT)   
        {  
            i++;
            if(i >= UNIT_SIZE) i = 0;  
                master.state = MB_IDLE; 
        }       
     
        break;
    default:
        break;
    }
}

/**
 * @brief Modbus CRC16校验计算函数.
 * @param 
 *   - *dat         数据缓冲区指针.
 *   - len          数据长度.
 *
 * @return uint16_t CRC16校验值
 */
uint16_t modbus_crc16( uint8_t *dat, uint16_t len) 
{
    uint16_t crc = 0xFFFF;
    uint16_t i;
    uint8_t j;
    
    for (i = 0; i < len; i++) {
        crc ^= dat[i];
        for (j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc = crc >> 1;
            }
        }
    }
    return crc;
}
